package data.result;

import data.cad.CAD;
import data.component.BoundingBox;
import data.component.Ceiling;
import data.component.Wall;
import data.xml.XML;
import utils.Matrix;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 墙面(包括顶板地板)测量信息
 */
public class MeasureSurface {
    /**
     * 墙面ID（房间id为-1）
     */
    public String id;

    /**
     * 数据指标
     */
    public ArrayList<MeasureItem> measurements;

    /**
     * 多墙面对应墙面ID
     */
    public ArrayList<String> walls;

    /**
     * 墙面方位信息
     */
    public String direction;

    /**
     * 图纸ID
     */
    public String drawMapId;

    /**
     * 匹配分数
     */
    public double matchScore;

    /**
     * 墙面图纸坐标
     */
    public ArrayList<Double[]> wallCadCoordinate;

    /**
     * 对应绿线id
     */
    public ArrayList<String> mappingIds;

    public void CompleteWallSurface(CAD cad, HashMap<String, Wall> map,  Matrix matrix, Double angle)
    {
        setMappingIds(cad.walls, map);
        var mapWall = CAD.GetLongestMappingWallByXmlWallId(cad.walls, map, this.id);
        if (mapWall != null)
        {
            setDrawMapId(mapWall.id);
            setMatchScore(mapWall, map);
            setWallCadCoordinate(cad.walls, map);
        }
        this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle, drawMapId, matchScore));
    }

    public void CompleteMultiWallSurface(CAD cad, HashMap<String, Wall> map,  Matrix matrix, Double angle)
    {
        if (this.walls.isEmpty())
        {
            this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle, null, null));
            return;
        }
        var mapWall1 = CAD.GetLongestMappingWallByXmlWallId(cad.walls, map, this.walls.get(0));
        var mapWall2 = CAD.GetLongestMappingWallByXmlWallId(cad.walls, map, this.walls.get(1));
        if (mapWall1 != null && mapWall2!= null)
        {
            setDrawMapId(mapWall1.id, mapWall2.id);
            setMatchScore(mapWall1, mapWall2, map);
        }
        this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle, drawMapId, matchScore));
    }

    public void CompleteOpeningSurface(CAD cad, HashMap<String, Wall> map, Matrix matrix, Double angle, HashMap<String, Integer> wallOpeningCount)
    {
        if (this.walls.isEmpty())
        {
            this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle, null, null));
            return;
        }
        var mapWall = CAD.GetLongestMappingWallByXmlWallId(cad.walls, map, this.walls.get(0));
        if (mapWall != null)
        {
            int count =1;
            if(wallOpeningCount.containsKey(mapWall.id))
            {
                count = wallOpeningCount.get(mapWall.id) + 1;
            }
            wallOpeningCount.put(mapWall.id, count);
            setDrawMapId(mapWall.id, count);
            setMatchScore(mapWall, map);
        }
        this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle, null, null));
    }

    public void CompleteRoomSurface(CAD cad, XML xml, HashMap<String, Wall> map, Matrix matrix, Double angle)
    {
        this.measurements.forEach(m -> m.SetMeasureItem(cad, xml, map,  matrix, angle));
    }

    public void CompleteCeilingSurface(CAD cad, XML xml, HashMap<String, Wall> map, Matrix matrix, Double angle)
    {
        SetDrawMapId(xml.ceilings);
        this.measurements.forEach(m -> m.SetMeasureItem(cad, map,  matrix, angle));
    }

    public void CompleteFloorSurface(CAD cad, HashMap<String, Wall> map, Matrix matrix, Double angle)
    {
        this.measurements.forEach(m -> m.SetMeasureItem(cad, map, matrix, angle));
    }




    private void setMappingIds(List<Wall> walls, HashMap<String, Wall> map) {
        var mapWalls = CAD.GetMappingWallsByXmlWallId(walls, map, this.id);
        this.mappingIds = (ArrayList<String>) mapWalls.stream().map(wall -> wall.id).collect(Collectors.toList());
    }

    private void setDrawMapId(String mapWall1Id, String mapWall2Id) {
        this.drawMapId = mapWall1Id + "_" + mapWall2Id;
    }

    private void setDrawMapId(String mapWallId) {
        this.drawMapId = mapWallId;
    }
    
    private void setDrawMapId(String mapWallId, int index){
        this.drawMapId = mapWallId + "_" + index;
    }

    private void SetDrawMapId(List<Ceiling> ceilings)
    {
        var filterCeilings = ceilings.stream().filter(ceiling -> ceiling.id.equals(this.id)).collect(Collectors.toList());
        if (!filterCeilings.isEmpty()){
            this.drawMapId = ceilings.get(0).code;
        }
    }

    private void setMatchScore(Wall mapWall,  HashMap<String, Wall> map) {
//        this.matchScore = map.get(mapWall.id) != null ? map.get(mapWall.id).scanQuality : 0;
        this.matchScore = Math.random();
    }

    private void setMatchScore(Wall mapWall1, Wall mapWall2, HashMap<String, Wall> map) {
//        var score1 =  mapWall1!=null &&map.get(mapWall1.id) != null ? map.get(mapWall1.id).scanQuality : 0;
//        var score2 =  mapWall2!=null &&map.get(mapWall2.id) != null ? map.get(mapWall2.id).scanQuality : 0;
//        this.matchScore = score1 + score2;
        this.matchScore = Math.random();
    }


    private void setWallCadCoordinate(List<Wall> cadWalls,HashMap<String, Wall> map ) {
        var walls = CAD.GetMappingWallsByXmlWallId(cadWalls, map, this.id);
        if (walls.isEmpty())
            return;
        var points = new ArrayList<Double[]>();
        for (var wall : walls)
        {
            points.add(wall.start);
            points.add(wall.end);
        }
        var bBox = new BoundingBox(points);
        this.wallCadCoordinate = new ArrayList<>(Arrays.asList(bBox.min, bBox.max));
    }

}

